﻿#region Licence
/*
 * Copyright (c) 2008, 2009, SmartGrid.NET Ltd
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 *
 * Neither the name of SmartGrid.NET Ltd nor the names of its contributors 
 * may be used to endorse or promote products derived from this software 
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * 
 */
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Configuration;

using log4net;


namespace ServiceBroker.NUnit.Utils
{
    public class XmlConfigurator : IConfigurationSectionHandler
    {
        #region Logging
        private static readonly ILog _log = LogManager.GetLogger(typeof(XmlConfigurator));
        #endregion

        #region CtorDtor
        XmlConfigurator()
        {
        }
        #endregion

        static public object DeserializeXmlConfiguration(XmlNode section)
        {
            XPathNavigator navigator = section.CreateNavigator();
            String typeName = (string)navigator.Evaluate("string(@type)");
            Type sectionType = Type.GetType(typeName, true, true);

            XmlSerializer xs = new XmlSerializer(sectionType);
            XmlNodeReader reader = new XmlNodeReader(section);

            return xs.Deserialize(reader);
        }

        #region IConfigurationSectionHandler Members

        object IConfigurationSectionHandler.Create(object parent, object configContext, XmlNode section)
        {
            Object settings = null;

            if (section == null) { return settings; }

            settings = DeserializeXmlConfiguration(section);

            return settings;
        }

        #endregion
    }


    public class CfgHelper
    {
        #region Logging
        private static readonly ILog _log = LogManager.GetLogger(typeof(CfgHelper));
        #endregion

        #region CtorDtor
        CfgHelper()
        {
        }
        #endregion

        #region Config
        protected T SetConfig<T>(XmlNode cfgNode, string xpath)
            where T : new()
        {
            return SetConfig<T>(cfgNode, xpath, false);
        }


        protected T SetConfig<T>(XmlNode cfgNode, string xpath, bool allowNULL)
            where T : new()
        {
            T cfg = default(T);

            try
            {
                if (null != cfgNode && null != xpath)
                {
                    try
                    {
                        XmlSerializer xs = new XmlSerializer(typeof(T));
                        cfg = (T)xs.Deserialize(new XmlNodeReader(cfgNode));
                    }
                    catch (System.InvalidOperationException) { }

                    if (null == cfg)
                    {
                        XmlNode node = cfgNode.SelectSingleNode(xpath);
                        if (null != node)
                        {
                            try
                            {
                                XmlSerializer xs = new XmlSerializer(typeof(T));
                                cfg = (T)xs.Deserialize(new XmlNodeReader(node));
                            }
                            catch (System.InvalidOperationException) { }
                        }
                    }

                    if (null == cfg)
                    {
                        XmlNode node = cfgNode.SelectSingleNode("//" + xpath);
                        if (null != node)
                        {
                            try
                            {
                                XmlSerializer xs = new XmlSerializer(typeof(T));
                                cfg = (T)xs.Deserialize(new XmlNodeReader(node));
                            }
                            catch (System.InvalidOperationException) { }
                        }
                    }

                    if (!allowNULL && null == cfg)
                    {
                        string msg = string.Format("Expected Configuration for type [{0}] using XPath [{1}] from the following Xml: {2}",
                            typeof(T).ToString(), xpath, cfgNode.OuterXml);
                        ApplicationException e = new ApplicationException(msg);

                        _log.Error(msg);
                        throw e;
                    }
                    else
                    {
                        if (allowNULL)
                            _log.InfoFormat("No configuration of type[{0}] using XPath[{1}] from Xml[{2}]", typeof(T).ToString(), xpath, cfgNode.OuterXml);
                        else
                            _log.InfoFormat("Successful configuration of type[{0}] using XPath[{1}] from Xml[{2}]", typeof(T).ToString(), xpath, cfgNode.OuterXml);
                    }
                }
            }
            catch (ApplicationException)
            {
                throw;
            }
            catch (Exception e)
            {
                string msg = string.Format("Unexpected Exception getting Configuration for type [{0}] using XPath [{1}] from the following Xml: {2}",
                    typeof(T).ToString(), ((null == xpath) ? "NULL" : xpath), ((null == cfgNode) ? "NULL" : cfgNode.OuterXml));

                _log.Error(msg, e);
                throw e;
            }

            return cfg;
        }
        #endregion
    }
}
